package com.slofzx.nuoda.evaluation.project.compont.imported;

import com.alibaba.fastjson.JSON;
import com.slofzx.nuoda.common.config.Type;
import com.slofzx.nuoda.common.enums.CommonResultEnum;
import com.slofzx.nuoda.common.enums.ServiceResult;
import com.slofzx.nuoda.common.exception.ServiceException;
import com.slofzx.nuoda.common.feign.FileInfoClient;
import com.slofzx.nuoda.common.util.DataConvertUtil;
import com.slofzx.nuoda.evaluation.project.enums.ProductTypeEnum;
import com.slofzx.nuoda.evaluation.project.compont.AbstractExcelComponent;
import com.slofzx.nuoda.evaluation.project.dto.BatchCommonDataDTO;
import com.slofzx.nuoda.evaluation.project.dto.ProjectInfoSaveDTO;
import com.slofzx.nuoda.evaluation.project.dto.ProjectYearDataDTO;
import com.slofzx.nuoda.evaluation.project.enums.*;
import com.slofzx.nuoda.evaluation.project.observer.BatchObserver;
import com.slofzx.nuoda.evaluation.project.util.BusiUtil;
import com.slofzx.nuoda.excel.vo.ExcelPreviewDataVO;
import com.slofzx.nuoda.excel.vo.SheetConfigVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Component
public abstract class AbstractImportExcelComponent extends AbstractExcelComponent {

    @Autowired
    private FileInfoClient fileInfoClient;
    @Autowired(required = false)
    protected Set<BatchObserver> batchObservers;

    public ServiceResult importExcel(ImportExcelContext context) {
        ResponseEntity<byte[]> responseEntity = fileInfoClient.downloadFile(context.getFileId());
        if (null == responseEntity) {
            return CommonResultEnum.VALUE_LOOSE;
        }
        InputStream inputStream = new ByteArrayInputStream(responseEntity.getBody());
        //解析上传文件数据，获取字段值
        ExcelPreviewDataVO uploadFileData = null;
        try {
            uploadFileData = excelService.previewDownloadWorkbook(inputStream);
        } catch (Exception e) {
            return CommonResultEnum.FILE_READERROR;
        }

        final ExcelPreviewDataVO templateFileData = getExcelPreviewData(getTemplatePath(context.getProductType()),false);
        String targetId = context.getId();
        COMPANY_MAP = new HashMap<>();
        OIL_FILED_NAME_MAP = new HashMap<>();
        for (int i = 0; i < templateFileData.getSheetList().size(); i++) {
//            if (i == templateFileData.getSheetList().size() - 1) {
//                continue;
//            }

            final SheetConfigVO sheetConfigVO = (SheetConfigVO) templateFileData.getSheetList().get(i);
            // 获取坐标对应位置
            Map<String, String> fieldPositionMap =getFieldPositionMap(sheetConfigVO);
            final List<SheetConfigVO> sheetList = uploadFileData.getSheetList();
            final SheetConfigVO sheet = sheetList.get(i);
            if (i == 0) {
                importCostEVAMethod(targetId,fieldPositionMap,sheet);
                importBatchCommonData(targetId, fieldPositionMap, sheet);
            } else if (i == 1) {
                importProjectData(context, fieldPositionMap, sheet);
            } else {
                return CommonResultEnum.VALUE_INVALID;
            }
        }
        // 删除老的评价结果数据
        deleteOldComputeVersion(targetId);

        return CommonResultEnum.SUCCESS;
    }

    // 删除老的评价结果数据
    private void deleteOldComputeVersion(String targetId) {
        for (BatchObserver batchObserver : batchObservers) {
            if (batchObserver.getName().equals("project-compute-version")){
                // 异步删除
                CompletableFuture.runAsync(()-> batchObserver.handleBatchDelete(targetId));
            }
        }
    }

    /**
     * 导入任务成本本计算方法
     * @param
     * @param fieldPositionMap
     * @param sheet
     */
    private void importCostEVAMethod(String targetId, Map<String, String> fieldPositionMap, SheetConfigVO sheet) {
        final String position = fieldPositionMap.get("costEvaMethod");
        String[] split = position.split(BusiUtil.DELIMITER);
        Integer rowIndex = Integer.valueOf(split[0]);
        String colStr = split[1];

        List<Map<String, String>> dataList = sheet.getDataList();
        if (dataList.size() == 0) {
            return;
        }
        final Map<String, String> rowData = dataList.get(rowIndex);
        final String enumId = getEnumId(rowData.get(colStr), CostEvaMethodEnum.class);
        // 变更评价方法
        updateCostEvaMethod(targetId,enumId);
    }

    public abstract String getTemplatePath(ProductTypeEnum productType);

    public abstract void  updateCostEvaMethod(String targetId,String evaMethod) ;

    public abstract String getMapType(Map<String, String> fieldPositionMap,Map<String, String> rowData);

    public abstract void checkProject(Map<String, String> fieldPositionMap,List<Map<String, String>> dataList,Integer startRowIndex);
    /**
     * 导入项目数据
     *
     * @param
     * @param fieldPositionMap
     * @param sheet
     */
    private void importProjectData( ImportExcelContext context, Map<String, String> fieldPositionMap, SheetConfigVO sheet) {
        // 获取起始行
        String targetId = context.getId();
        final String indexPosition = fieldPositionMap.get("index");

        String[] indexSplit = indexPosition.split(BusiUtil.DELIMITER);
        String startRowIndexStr = indexSplit[0];
        List<Map<String, String>> dataList = sheet.getDataList();
        if (dataList.size() == 0) {
            return;
        }
        final Integer index = Integer.valueOf(startRowIndexStr);
        // 遍历每一行数据
        List<ProjectInfoSaveDTO> projectInfoDTOS = new ArrayList<>();
        Map<String, Map<ImportExcelYearDataConfigEnum, Map<Integer, Double>>> nameTypeYearDataMap = new HashMap<>();
        // 任务性质为方案的项目数量最多为3个且评价方法不能有重复的，同时不允许有地面评价的项目
        checkProject(fieldPositionMap,dataList,index);
        for (int i = index; i < dataList.size(); i++) {
            Map<String, String> rowData = dataList.get(i);
            Map<String, Object> dataMap = new HashMap<>();
            // 遍历每一个属性
            // 获取数据map类型
            String type = getMapType(fieldPositionMap,rowData);
            Map<ImportExcelYearDataConfigEnum, Map<Integer, Double>> typeYearDataMap = new HashMap<>();
            for (Map.Entry<String, String> fieldPositionEntry : fieldPositionMap.entrySet()) {
                final String position = fieldPositionEntry.getValue();
                String[] split = position.split(BusiUtil.DELIMITER);
                String colIndexStr = split[1];
                Integer colIndex =  getColIndex(fieldPositionEntry.getValue());
                // 加载项目数据和年份数据
                final String field = fieldPositionEntry.getKey();
                ImportExcelYearDataConfigEnum configEnum = BusiUtil.getEnumById(field,
                        ImportExcelYearDataConfigEnum.class);
                if (configEnum != null) {
                    final Map<Integer, Double> yearDataMap = getYearDataMap(colIndex, rowData, configEnum);
                    typeYearDataMap.put(configEnum, yearDataMap);
                } else {
                    final Object fieldValue = rowData.get(colIndexStr);
                    dataMap.put(field, convertData(context.getProductType(), field, fieldValue));
                }

            }

            nameTypeYearDataMap.put(type, typeYearDataMap);
            final ProjectInfoSaveDTO projectInfo = JSON.parseObject(JSON.toJSONString(dataMap), ProjectInfoSaveDTO.class);
            projectInfoDTOS.add(projectInfo);

        }
        // 数据保存
        final Map<String, String> projectMap = projectInfoService.importExcelData(targetId, context.getBatchQuality(), projectInfoDTOS);
        // 年份数据加载
        List<ProjectYearDataDTO> projectYearDataList = new ArrayList<>();
        for (String type : nameTypeYearDataMap.keySet()) {
            // 遍历项目数据
            final Map<ImportExcelYearDataConfigEnum, Map<Integer, Double>> importExcelYearDataConfigEnumListMap = nameTypeYearDataMap.get(type);
            if (MapUtils.isEmpty(importExcelYearDataConfigEnumListMap)) {
                continue;
            }

            List<Triple<ImportExcelYearDataConfigEnum, Integer, Double>> tripleList = new ArrayList<>();
            // 数据转换便于生成保存对象，按照年份统计
            for (ImportExcelYearDataConfigEnum dataConfigEnum : importExcelYearDataConfigEnumListMap.keySet()) {
                final Map<Integer, Double> mapList = importExcelYearDataConfigEnumListMap.get(dataConfigEnum);
                for (Map.Entry<Integer, Double> integerDoubleEntry : mapList.entrySet()) {
                    final Triple<ImportExcelYearDataConfigEnum, Integer, Double> triple = Triple.of(dataConfigEnum, integerDoubleEntry.getKey(), integerDoubleEntry.getValue());
                    tripleList.add(triple);
                }

            }
            final Map<Integer, List<Triple<ImportExcelYearDataConfigEnum, Integer, Double>>> listMap = tripleList.stream().collect(Collectors.groupingBy(Triple::getMiddle));
            // 组装对象
            for (Integer year : listMap.keySet()) {
                Map<String, Object> dataMap = new HashMap<>();
                final List<Triple<ImportExcelYearDataConfigEnum, Integer, Double>> triples = listMap.get(year);
                if (CollectionUtils.isEmpty(tripleList)) {
                    continue;
                }
                for (Triple<ImportExcelYearDataConfigEnum, Integer, Double> triple : triples) {
                    final ImportExcelYearDataConfigEnum dataConfigEnum = triple.getLeft();
                    dataMap.put(dataConfigEnum.getId(), triple.getRight());
                }
                dataMap.put("year", year);
                dataMap.put("batchId", targetId);
                dataMap.put("projectId", projectMap.get(type));
                ProjectYearDataDTO projectYearDataDTO = JSON.parseObject(JSON.toJSONString(dataMap), ProjectYearDataDTO.class);
                projectYearDataList.add(projectYearDataDTO);
            }
        }
        projectYearDataService.importExcelData(targetId, projectYearDataList);

    }


    private Object convertData(ProductTypeEnum productType, String field, Object fieldValue) {
        if (productType == null) {
            throw new ServiceException("产品类别不能为空", "产品类别不能为空", null);
        }
        switch (field) {
            case "year":
            case "buildYearCount":
            case "evaluationPeriod":
            case "fixedPerson":
            case "productionDay":
                return DataConvertUtil.parse2Int(fieldValue);
            case "productProperty":
                return convertEnumToId(fieldValue, OilProductPropertyEnum.class, OilProductPropertyEnum.class, productType);
            case "areaMark":
                return getEnumId((String) fieldValue, AreaMarkEnum.class);
            case "region":
                return convertEnumToId(fieldValue, OilRegionEnum.class, GasRegionEnum.class, productType);
            case "capacityType":
                return convertEnumToId(fieldValue, OilCapacityTypeEnum.class, GasCapacityTypeEnum.class, productType);
            case "displacementMethod":
                return convertEnumToId(fieldValue, OilDisplacementMethodEnum.class, GasDisplacementMethodEnum.class, productType);
            case "poolType":
                return convertEnumToId(fieldValue, OilPoolTypeEnum.class, GasPoolTypeEnum.class, productType);
            case "evaluationMethod":
                return getEnumId((String) fieldValue, EvaluationMethodEnum.class);
            case "buildOffice":
                return getCompanyId((String) fieldValue);
            case "oilGasField":
                return getOilGasFieldId((String) fieldValue);
            case "other1":
                return getEnumId((String) fieldValue, Other1Enum.class);
            case "other2":
                return getEnumId((String) fieldValue, Other2Enum.class);
            case "name":
                return fieldValue;
            default:
                return DataConvertUtil.parse2Double(fieldValue);

        }
    }

    private String convertEnumToId(Object fieldValue, Class<? extends Type> oilClazz,
                                   Class<? extends Type> gasClazz, ProductTypeEnum productType) {
        if (productType == ProductTypeEnum.OIL) {
            return getEnumId((String) fieldValue, oilClazz);
        } else {
            return getEnumId((String) fieldValue, gasClazz);
        }
    }

    private String getEnumId(String fieldValue, Class<? extends Type> clazz) {
        final Type enumByName = BusiUtil.getEnumByName(fieldValue, clazz);
        if (Objects.nonNull(enumByName)) {
            return enumByName.getId();
        }
        return null;
    }

    /**
     * 导入任务公共参数
     *
     * @param targetId
     * @param fieldPositionMap
     * @param sheet
     */
    private void importBatchCommonData(String targetId, Map<String, String> fieldPositionMap, SheetConfigVO sheet) {
        final String position = fieldPositionMap.get(ImportExcelYearDataConfigEnum.BATCH_YEAR_PARAM.getId());
        String[] split = position.split(BusiUtil.DELIMITER);
        String rowIndexStr = split[0];
        List<Map<String, String>> dataList = sheet.getDataList();
        if (dataList.size() == 0) {
            return;
        }
        final Integer index = Integer.valueOf(rowIndexStr);
        Map<String, Map<Integer, Double>> rowYearDataMap = new HashMap<>();
        Integer colIndex =  getColIndex(position);
        for (int i = index; i <  dataList.size(); i++) {
            Map<String, String> rowData = dataList.get(i);
            final String typeName = rowData.get(COL_STR+(colIndex - 1));
            final Map<Integer, Double> yearDataMap = getYearDataMap(colIndex, rowData, ImportExcelYearDataConfigEnum.BATCH_YEAR_PARAM);
            rowYearDataMap.put(typeName, yearDataMap);
        }
        if (MapUtils.isEmpty(rowYearDataMap)) {
            return;
        }
        Map<String, ImportExcelBatchParamTypeEnum> nameParamTypMap = new HashMap<>();
        for (ImportExcelBatchParamTypeEnum typeEnum : ImportExcelBatchParamTypeEnum.values()) {
            nameParamTypMap.put(typeEnum.getName(), typeEnum);
        }
        Map<Integer, List<Triple<String, Integer, Double>>> yearTypeMap = new HashMap<>();
        List<Triple<String, Integer, Double>> tripleList = new ArrayList<>();
        for (Map.Entry<String, Map<Integer, Double>> listEntry : rowYearDataMap.entrySet()) {
            for (Map.Entry<Integer, Double> integerDoubleEntry : listEntry.getValue().entrySet()) {
                final Triple<String, Integer, Double> triple = Triple.of(listEntry.getKey(), integerDoubleEntry.getKey(), integerDoubleEntry.getValue());
                tripleList.add(triple);

            }
        }
        if (CollectionUtils.isEmpty(tripleList)) {
            return;
        }
        // 年份map
        yearTypeMap = tripleList.stream().collect(Collectors.groupingBy(Triple::getMiddle));
        List<BatchCommonDataDTO> batchCommonDataList = new ArrayList<>();
        if (MapUtils.isEmpty(yearTypeMap)) {
            return;
        }
        for (Map.Entry<Integer, List<Triple<String, Integer, Double>>> listEntry : yearTypeMap.entrySet()) {
            Map<String, Object> map = new HashMap<>();
            for (Triple<String, Integer, Double> triple : listEntry.getValue()) {
                final ImportExcelBatchParamTypeEnum importExcelBatchParamTypeEnum = nameParamTypMap.get(triple.getLeft());
                if (importExcelBatchParamTypeEnum == null) {
                    continue;
                }
                map.put(importExcelBatchParamTypeEnum.getId(), triple.getRight());

            }
            map.put("year", listEntry.getKey());
            map.put("batchId", targetId);
            BatchCommonDataDTO commonDataDTO = JSON.parseObject(JSON.toJSONString(map), BatchCommonDataDTO.class);
            batchCommonDataList.add(commonDataDTO);
        }
        batchCommonDataService.batchInsertData(targetId, batchCommonDataList);
    }



    private Map<Integer, Double> getYearDataMap(Integer colIndexStr, Map<String, String> rowData, ImportExcelYearDataConfigEnum dataConfigEnum) {
        Map<Integer, Double> map = new HashMap<>();
        int year = dataConfigEnum.getYear();


        for (int i = 0; i <= year; i++) {

            final double fieldYearValue = DataConvertUtil.parse2Double(rowData.get(COL_STR+(colIndexStr + i)));
            if (fieldYearValue == 0) {
                continue;
            }
            int yearKey = i + 1;
            if (dataConfigEnum.isTotal()) {
                yearKey = i;
            } else {
                if (year == i) {
                    continue;
                }
            }
            map.put(yearKey , fieldYearValue);
            // yearDataList.add(map);

        }
        return map;
    }
}
